import random
import re
from datetime import datetime

from flask import request, abort, current_app, make_response, jsonify, session

from info import redis_store, constants, db
from info.libs.yuntongxun.sms import CCP
from info.models import User
from info.utils.captcha.captcha import captcha
from info.utils.captcha.response_code import RET
from . import passport_blu

@passport_blu.route('/login',methods=['POST','GET'])
def login():
    '''
    获取参数
    校验参数
    保存用户的登录状态
    响应
    :return:
    '''
    # 获取参数
    params=request.json
    mobile=params.get('mobile')
    passport=params.get('passport')

    # 校验参数
    if not all([mobile,passport]):
        return jsonify(errno=RET.PARAMERR,errmsg='参数填写错误')

    if not (re.match('1[35678]\\d{9}',mobile) and len(mobile)<=11):
        return jsonify(errno=RET.PARAMERR,errmsg='手机号输入有误')

    # 检查手机号的用户是否已经注册,校验密码是否正确
    try:
        user=User.query.filter(User.mobile==mobile).first()
    except Exception as r:
        current_app.logger.error(r)
        return jsonify(errno=RET.DATAERR,errmsg='用户查询错误')

    if not user:
        return jsonify(errno=RET.NODATA,errmsg='该手机用户不存在')

    # 校验登录密码和用户的密码是否一致
    if not user.check_password(passport):
        return jsonify(errno=RET.PWDERR,errmsg='密码或用户名输入错误')

    # 手机号密码正确,保存数据的登录状态
    session['user_id']=user.id
    session['mobile']=user.mobile
    session['nick_name']=user.nick_name

    # 用户每次登录刷新用户的登录状态
    user.last_login=datetime.now()
    # 更改了数据库里时间登录数据,需要commit()提交
    '''
    如果在视图函数中,对模型身上的属性有修改,那么需要commit到数据库
    进行保存,但其实可以不用自己去写db.session.commit(),但前提是
    SQLAlchemy对相关配置进行了设置
    '''
    # try:
    #     db.session.commit()
    # except Exception as r:
    #     current_app.logger.error(r)
    #     db.session.rollback()
    #     return jsonify(errno=RET.DATAERR,errmsg='时间更新失败')

    # 响应
    return jsonify(errno=RET.OK,errmsg='登录成功')

@passport_blu.route('/logout')
def logout():
    '''
    点击退出按钮,移除session里面的数据,用pop方法
    :return:
    '''
    # pop会有一个返回值,如果移除的数据为空,返回None
    session.pop('mobile',None)
    session.pop('nick_name',None)
    session.pop('user_id',None)
    # 如果不清除,管理用户退出后,普通用户能直接取到is_admin的值,可以直接访问到管理后台
    session.pop('is_admin', None)

    return jsonify(errno=RET.OK,errmsg='退出成功')


@passport_blu.route('/register',methods=['POST','GET'])
def register():
    # 取出参数
    params_dict=request.json
    mobile=params_dict.get('mobile')
    smscode=params_dict.get('smscode')
    passport=params_dict.get('passport')

    # 校验参数
    # 检验用户是否已经注册过
    user=User.query.filter(User.nick_name==mobile).first()
    if user:
        return jsonify(errno=RET.USERERR,errmsg='用户已经存在')

    if not all([mobile,smscode,passport]):
        return jsonify(errno=RET.PARAMERR,errmsg='参数错误')

    # 判断手机号
    if not (re.match('1[35678]\\d{9}',mobile) and len(mobile)<=11):
        return jsonify(errno=RET.PARAMERR,errmsg='手机号输入有误')

    # 取存放在redis里真实的短信验证码
    try:
        real_sms_code=redis_store.get('SMS_'+mobile)
    except Exception as r:
        current_app.logger.error(r)
        return jsonify(errno=RET.DBERR, errmsg='数据查询错误')

    if not real_sms_code:
        return jsonify(errno=RET.NODATA, errmsg='验证码已过期')

    # 如果存在,验证是否和输入的短信验证码一样
    if real_sms_code != smscode:
        return jsonify(errno=RET.DATAERR, errmsg='验证码输入错误')

    # 如果验证码一样,初始化User模型,并实例化属性
    user=User()
    user.mobile=mobile
    # 昵称用手机号代替
    user.nick_name=mobile
    user.last_login=datetime.now()
    # 对密码进行处理,设置密码,会调用设置函数对密码进行加密
    user.password=passport

    # 将数据存储在数据库中
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as r:
        current_app.logger.error(r)
        db.session.rollback()
        return jsonify(errno=RET.DATAERR, errmsg='数据提交错误')

    # 往session保存数据表示当前已经登录
    session['user_id']=user.id
    session['mobile']=user.mobile
    session['nick_name']=user.nick_name

    return jsonify(errno=RET.OK, errmsg='发送成功')


@passport_blu.route('/sms_code',methods=['POST','GET'])
def send_sms_code():
    # 获取参数:手机号
    # params_dict=json.loads(request.data)
    # return jsonify(errno=RET.OK,errmsg='发送成功')
    params_dict=request.json

    mobile=params_dict.get('mobile')
    image_code=params_dict.get('image_code')
    image_code_id=params_dict.get('image_code_id')

    # 判断参数是否有值
    if not all([mobile,image_code,image_code_id]):
        return jsonify(errno=RET.PARAMERR,errmsg='参数有误')
    # 校验手机号是否正确
    if not (re.match('1[35678]\\d{9}',mobile) and len(mobile)<=11):
        return jsonify(errno=RET.PARAMERR,errmsg='手机号输入有误')
    # 先从redis中去除真实的验证码内容
    try:
        real_image_code=redis_store.get('imageCodeId'+image_code_id)
    except Exception as r:
        current_app.logger.error(r)
        return jsonify(errno=RET.DBERR,errmsg='数据库查询失败')

    if not real_image_code:
        return jsonify(errno=RET.NODATA,errmsg='图片验证码已过期')
    # 与用户的验证码内容进行对比,如果对比不一致,那么返回验证码输入错误
    if real_image_code.upper() != image_code.upper():
        return jsonify(errno=RET.DATAERR,errmsg='验证码输入错误')

    # 如果一致,生成短信验证码的内容
    # 随机数字,保证数字长度为6位,不够在前面补全
    sms_code_str='%06d' % random.randint(0,999999)
    current_app.logger.debug("短信验证码内容是:%s" % sms_code_str)

    # 发送短信验证码
    # result=CCP().send_template_sms(mobile,[sms_code_str,constants.SMS_CODE_REDIS_EXPIRES/5],'1')
    # if result !=0:
    #     # 代表发送不成功
    #     return jsonify(errno=RET.THIRDERR,errmsg='短信发送不成功')

    # 反之发送成功,保存验证码内容到redis
    try:
        redis_store.set('SMS_'+mobile,sms_code_str,constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as r:
        current_app.logger.error(r)
        return jsonify(errno=RET.DBERR, errmsg='数据保存失败')

    # 验证码发送成功
    return jsonify(errno=RET.OK,errmsg='发送成功')

@passport_blu.route('/image_code')
def get_image_code():
    # 取到参数
    image_code_id=request.args.get('imageCodeId',None)

    # 判断参数是否有值
    if not image_code_id:
        return abort(403)

    # 生成图片验证码
    name,text,image=captcha.generate_captcha()
    print(text)
    # 保存图片验证码文字到redis
    try:
        redis_store.set('imageCodeId'+image_code_id,text,constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as r:
        current_app.logger.error(r)
        abort(500)

    response=make_response(image)

    #设置数据类型,以便浏览器更加智能识别他是什么类型
    response.headers['Content-Type']='image/jpg'
    # 返回验证码图片
    return response
